
import java.awt.event.KeyEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.Cursor;
import java.awt.Event;
import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.Dialog.ModalityType;

import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.KeyStroke;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JMenuItem;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JFrame;
import javax.swing.JDialog;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import java.awt.Dimension;

import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.border.EmptyBorder;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import javax.swing.JToolBar;
import javax.swing.JRadioButton;
import javax.swing.JButton;
import java.awt.GridBagLayout;
import javax.swing.JTextField;
import java.awt.GridBagConstraints;
import java.io.IOException;
import java.net.URL;
import java.util.Iterator;

import javax.swing.JPasswordField;
import javax.xml.parsers.ParserConfigurationException;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.filter.ElementFilter;
import org.jdom.transform.XSLTransformException;
import org.jdom.transform.XSLTransformer;

import net.juniper.netconf.Device;

/**
 * Application running on a JFrame that allows working on a user/pasword database that will later
 * be published on a SRX device for Dynamic VPN applications
 * @author xhagesta
 *
 */
public class MainWindow implements ActionListener, WindowListener {

//	Collection of swing elements
	private JFrame jFrame = null;  //  @jve:decl-index=0:visual-constraint="8,6"
	private JPanel jContentPane = null;  //  @jve:decl-index=0:
	private JMenuBar jJMenuBar = null;  //  @jve:decl-index=0:
	private JMenu fileMenu = null;
	private JMenu editMenu = null;
	private JMenu helpMenu = null;
	private JMenuItem exitMenuItem = null;
	private JMenuItem aboutMenuItem = null;
	private JMenuItem addMenuItem = null;
	private JMenuItem deleteMenuItem = null;
	private JMenuItem saveMenuItem = null;
	private JMenuItem openMenuItem = null;
	private JMenuItem importMenuItem = null;
	private JDialog aboutDialog = null;  //  @jve:decl-index=0:visual-constraint="635,10"
	private JPanel aboutContentPane = null;
	private JLabel aboutVersionLabel = null;
	private JScrollPane UsersScrollPanel = null;
	private JTable UsersTable = null;
	private JToolBar StatusToolBar = null;
	private JMenuItem PreferencesMenuItem = null;
	private JRadioButton ConnectedButton = null;
	private JButton CommitButton = null;
	private JDialog addUserDialog = null;  //  @jve:decl-index=0:visual-constraint="633,71"
	private JPanel userPasswordPanel = null;
	private JTextField usernameEntryField = null;
	private JPasswordField passwordEntryField = null;
	private JPanel okCancelPanel1 = null;
	private JButton userAddOkButton = null;
	private JButton userAddCancelButton = null;
	private JDialog PreferencesDialog = null;  //  @jve:decl-index=0:visual-constraint="645,200"
	private JPanel preferenceFieldsPanel = null;
	private JTextField ipAddressEntryField = null;
	private JTextField adminUserEntryField = null;
	private JPasswordField adminPasswordEntryField = null;
	private JTextField remoteNetworkEntryField = null;
	private JTextField remoteLowIpEntryField = null;
	private JTextField remoteHighIpEntryField = null;
	private JTextField remoteDnsIpAddress = null;
	private JPanel preferencesOkCancelPanel = null;
	private JButton preferencesOkButton = null;
	private JButton preferencesCancelButton = null;
	private JDialog errorDialog = null;  //  @jve:decl-index=0:visual-constraint="275,361"
	private JPanel errorDialogContentPane = null;
	private JLabel errorDialogText = new JLabel("", SwingConstants.CENTER);
    private Image juniperIcon;
    private Cursor cursorDefault = new Cursor(Cursor.DEFAULT_CURSOR);
    private Cursor cursorWait = new Cursor(Cursor.WAIT_CURSOR);


//	JDOM document and root element used as dataSource to the applications core JTable
	private Document usersData = null;
	private Element profileElement = null;

//	This object will allow us perform basic password-based encryption and decryption
//  Functions to avoid exposing clear-text based password on exported files
	private basicCrypto bc = null;
	
//	This object has methods to load/save both application configuration data and user/password database into external files
    private configFile preferencesFile;

//  This XSL Transformation removes all <client> elements having the "selected" attribute from the JDOM document
    private XSLTransformer xlsPurger = null;
    
//  This XLS Transformation produces a exact copy of any XML document but without any single existing attribute.
//  We'll use it to cleanup the core JDOM document before being send over the Netconf connection 
    private XSLTransformer xlsNoattrs = null;

//  These variable will hold URL pointers to Schema validators includes in the jar package
    private URL xsdConfig = null;
    private URL xsdOpen = null;
    private URL xsdImport = null;
    private static final String XSDCONFIG = "resource/configFile.xsd";
    private static final String XSDOPEN = "resource/usersDataOpen.xsd";
    private static final String XSDIMPORT = "resource/usersDataImport.xsd";
    
//  This is the Netconf object we'll use to connect to the SRX
    private Device srxDevice = null;

//  Constants for state machine clearity
    private static final int TR_INIT = 0;
    private static final int TR_PREFLOADOK = 1;
    private static final int TR_PREFLOADNOK = 2;
    private static final int TR_PUSHCONNECT = 3;
    private static final int TR_CONNECTOK = 4;
    private static final int TR_AUTO = 5;
    private static final int TR_DIALOGCLOSE = 6;
    private static final int TR_PUSHCOMMIT = 7;
    private static final int ST_INIT = 0;
    private static final int ST_OFFLINE = 1;
    private static final int ST_READY = 2;
    private static final int ST_PRECONNECT = 3;
    private static final int ST_CONNOK = 4;
    private static final int ST_DISCONNECT = 5;
    private static final int ST_LOADPREFS = 6;
    private static final int ST_PREREADY = 7;
    private static final int ST_PREFSUPDATE = 8;
    private static final int ST_COMMIT = 9;
    
//  This variable holds the current state in the finite state machine. We start at INI state
    private int currentState = ST_INIT;

	/**
	 * Finite State Machine implementation for the whole application states
	 * @param transition	Transition event to drive the state machine
	 */
	private void stateMachine(int transition) {

//		LOADPREFS state: Init all Main objects and try to load the application configuration file
//		Triggers PREFLOADNOK to jump to OFFLINE state if there is any issue loading the configuration file
//		Triggers PREFLOADOK to jump to PREREADY if successfully loaded the configuration file
		if ( currentState == ST_INIT && transition == TR_INIT ) {
			currentState = ST_LOADPREFS;
			preferencesFile = new configFile(jFrame);
			profileElement = new Element("profile");
			usersData = new Document(profileElement);
			xsdConfig = getClass().getResource(XSDCONFIG);
			xsdOpen = getClass().getResource(XSDOPEN);
			xsdImport = getClass().getResource(XSDIMPORT);
			getPreferenceFieldsPanel();
			bc = new basicCrypto();
		    try {
				xlsNoattrs = new XSLTransformer(this.getClass().getResourceAsStream("resource/noAttibutes.xsl"));
				xlsPurger = new XSLTransformer(this.getClass().getResourceAsStream("resource/deletedUsers.xsl"));
			} catch (XSLTransformException e) {
//				There is no to handle this exception because we're providing a static reference
			}
			
			try {
				preferencesFile.getParams(xsdConfig);
			} catch (Throwable e){
				stateMachine(TR_PREFLOADNOK);
				return;
				}

			if (preferencesFile.preferencesLoaded) {
				stateMachine(TR_PREFLOADOK);
			}
			else stateMachine(TR_PREFLOADNOK);
			return;
		}
		
//		OFFLINE state: Just disable connect and commit buttons. We'll leave this state once the users settles
//		preferences for the application
		if ( currentState == ST_LOADPREFS && transition == TR_PREFLOADNOK) {
			currentState = ST_OFFLINE;
			ConnectedButton.setEnabled(false);
			CommitButton.setEnabled(false);
			return;
		}
		
//		PREREADY: We have preferences for the application so we must refresh main application variables
//		with data comming from the configuration file
//		Triggers AUTO to jump to READY stable state
		if ( ( currentState == ST_LOADPREFS && transition == TR_PREFLOADOK ) ||
			 ( currentState == ST_PREFSUPDATE && transition == TR_AUTO) ){
			currentState = ST_PREREADY;
			adminUserEntryField.setText(preferencesFile.adminUsername);
			adminPasswordEntryField.setText(preferencesFile.adminPassword);
			ipAddressEntryField.setText(preferencesFile.ipAddress);
			remoteNetworkEntryField.setText(preferencesFile.remoteNetwork);
			remoteLowIpEntryField.setText(preferencesFile.lowIp);
			remoteHighIpEntryField.setText(preferencesFile.highIp);
			remoteDnsIpAddress.setText(preferencesFile.dnsIp);
			ConnectedButton.setEnabled(true);
			stateMachine(TR_AUTO);
			return;
		}
		
//		PREFSUPDATE: The user has filled the preferences dialog so we must save them to the configuration file
//		Triggers AUTO to jump to PREREADY
		if ( (currentState == ST_OFFLINE && transition == TR_PREFLOADOK) ||
			 (currentState == ST_READY && transition == TR_PREFLOADOK) ) {
			currentState = ST_PREFSUPDATE;
			try {
				preferencesFile.setParams(ipAddressEntryField.getText(),
						                  adminUserEntryField.getText(),
						                  new String(adminPasswordEntryField.getPassword()),
						                  remoteNetworkEntryField.getText(),
						                  remoteLowIpEntryField.getText(),
						                  remoteHighIpEntryField.getText(),
						                  remoteDnsIpAddress.getText());
			} catch (IOException e1) {
//				An error writting the config file? The application might be running on a RO FileSystem of the
//				application may not have enough rights to writre to the file. No problem: the user will have
//				to fill the form next time he starts the application.
			}
			stateMachine(TR_AUTO);
			return;
		}

//		READY: Main hub state before a netconf connection to the srx is stablished
		if ( (currentState == ST_PREREADY && transition == TR_AUTO) ||
			 (currentState == ST_PRECONNECT && transition == TR_DIALOGCLOSE) ||
			 (currentState == ST_DISCONNECT && transition == TR_AUTO) || 
			 (currentState == ST_PREFSUPDATE && transition == TR_AUTO) ){
			currentState = ST_READY;
			return;
		}		
		
//		PRECONNECT: We'll try to stablish the netconf connection. We'll change connect and commit buttons values
//		Triggers CONNECTOK if everithing is OK
//		Triggers DIALOGCLOSE if there is any problem
		if ( currentState == ST_READY && transition == TR_PUSHCONNECT ) {
			currentState = ST_PRECONNECT;
//			This may take a while. Let's show the wait cursor
			getJFrame().setCursor(cursorWait);
		    try {
				srxDevice = new Device (preferencesFile.ipAddress, preferencesFile.adminUsername, preferencesFile.adminPassword);
			} catch (Exception e) {
				ConnectedButton.setSelected(false);
				ConnectedButton.setText("Push to connect");
				showErrorDialog(e.getMessage());
				return;
			}
			finally {
//				Well of bad we're done. Let's show the normal cursor
				getJFrame().setCursor(cursorDefault);
			}
			ConnectedButton.setSelected(true);
			ConnectedButton.setText("Push to disconnect");
			CommitButton.setEnabled(true);
			stateMachine(TR_CONNECTOK);
			return;
		}
		
//		CONNOK: Main hub state in the context of a successfull Netconf connection
		if ( ( currentState == ST_PRECONNECT && transition == TR_CONNECTOK ) ||
			 ( currentState == ST_COMMIT && transition == TR_DIALOGCLOSE )) {
			currentState = ST_CONNOK;
			return;
		}

//		DISCONNECT: Gracefully disconnection from SRX device. Disable commit button and change the label for the
//		connection button to the "connect" option
//		Triggers AUTO to jump to READY state
		if ( currentState == ST_CONNOK && transition == TR_PUSHCONNECT ) {
			currentState = ST_DISCONNECT;
//			This may take a while ...
			getJFrame().setCursor(cursorWait);
			ConnectedButton.setSelected(false);
			ConnectedButton.setText("Push to connect");
			srxDevice.close();
			CommitButton.setEnabled(false);
			getJFrame().setCursor(cursorDefault);
			stateMachine(TR_AUTO);
			return;
		}
		
//		COMMIT: We'll send the data to the SRX device over the Netconf connection
//		Triggers DIALOGCLOSE to jump to CONNOK no matter if we succed of fail
		if ( currentState == ST_CONNOK && transition == TR_PUSHCOMMIT ) {
			currentState = ST_COMMIT;
//			This may take a while so we change the cursor to wait
			getJFrame().setCursor(cursorWait);
			netconfInterface commitData = null;
			try {
				commitData = new netconfInterface();
			} catch (ParserConfigurationException e) {
//				There is no need to handle this exception because we build the document from static sources
				e.printStackTrace();
			}
			if ( commitData != null ) {
				try {
					commitData.commitConfig(remoteNetworkEntryField.getText(),
							                remoteLowIpEntryField.getText(),
							                remoteHighIpEntryField.getText(),
							                remoteDnsIpAddress.getText(),
							                xlsNoattrs.transform(usersData),
							                srxDevice);
				} catch (Exception e) {
					showErrorDialog(e.getMessage());
				}
			}
			getJFrame().setCursor(cursorDefault);
			stateMachine(TR_DIALOGCLOSE);
			return;
		}
	}
    
    /**
	 * This method initializes jFrame
	 * 
	 * @return javax.swing.JFrame
	 */
	private JFrame getJFrame() {
		if (jFrame == null) {
			jFrame = new JFrame();
			juniperIcon  = Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("/resource/icon1.gif"));
			jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			jFrame.setJMenuBar(getJJMenuBar());
			jFrame.setSize(617, 338);
			jFrame.setContentPane(getJContentPane());
			jFrame.setTitle("Juniper DynVPN User Manager");
			jFrame.setIconImage(juniperIcon);
			jFrame.setLocationRelativeTo(null);
			stateMachine(TR_INIT);
		}
		return jFrame;
	}
	
	/**
	 * This method initializes jContentPane
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getJContentPane() {
		if (jContentPane == null) {
			BorderLayout borderLayout = new BorderLayout();
			borderLayout.setHgap(8);
			jContentPane = new JPanel();
			jContentPane.setLayout(borderLayout);
			jContentPane.add(getUsersScrollPanel(), BorderLayout.CENTER);
			jContentPane.add(getStatusToolBar(), BorderLayout.SOUTH);
		}
		return jContentPane;
	}

	/**
	 * This method initializes jJMenuBar	
	 * 	
	 * @return javax.swing.JMenuBar	
	 */
	private JMenuBar getJJMenuBar() {
		if (jJMenuBar == null) {
			jJMenuBar = new JMenuBar();
			jJMenuBar.add(getFileMenu());
			jJMenuBar.add(getEditMenu());
			jJMenuBar.add(getHelpMenu());
		}
		return jJMenuBar;
	}

	/**
	 * This method initializes jMenu	
	 * 	
	 * @return javax.swing.JMenu	
	 */
	private JMenu getFileMenu() {
		if (fileMenu == null) {
			fileMenu = new JMenu("File");
			fileMenu.add(getOpenMenuItem());
			fileMenu.add(getSaveMenuItem());
			fileMenu.add(getImportMenuItem());
			fileMenu.add(getExitMenuItem());
		}
		return fileMenu;
	}

	/**
	 * This method initializes jMenu	
	 * 	
	 * @return javax.swing.JMenu	
	 */
	private JMenu getEditMenu() {
		if (editMenu == null) {
			editMenu = new JMenu("Edit");
			editMenu.add(getAddMenuItem());
			editMenu.add(getDeleteMenuItem());
			editMenu.add(getPreferencesMenuItem());
		}
		return editMenu;
	}

	/**
	 * This method initializes jMenu	
	 * 	
	 * @return javax.swing.JMenu	
	 */
	private JMenu getHelpMenu() {
		if (helpMenu == null) {
			helpMenu = new JMenu("Help");
			helpMenu.add(getAboutMenuItem());
		}
		return helpMenu;
	}

	/**
	 * This method initializes jMenuItem	
	 * 	
	 * @return javax.swing.JMenuItem	
	 */
	private JMenuItem getExitMenuItem() {
		if (exitMenuItem == null) {
			exitMenuItem = new JMenuItem("Exit");
			exitMenuItem.addActionListener(this);
		}
		return exitMenuItem;
	}

	/**
	 * This method initializes jMenuItem	
	 * 	
	 * @return javax.swing.JMenuItem	
	 */
	private JMenuItem getAboutMenuItem() {
		if (aboutMenuItem == null) {
			aboutMenuItem = new JMenuItem("About");
			aboutMenuItem.addActionListener(this);
		}
		return aboutMenuItem;
	}

	/**
	 * This method initializes aboutDialog	
	 * 	
	 * @return javax.swing.JDialog
	 */
	private JDialog getAboutDialog() {
		if (aboutDialog == null) {
			aboutDialog = new JDialog(getJFrame(), true);
			aboutDialog.setTitle("About");
			aboutDialog.setContentPane(getAboutContentPane());
			aboutDialog.setModalityType(ModalityType.APPLICATION_MODAL);
		}
		return aboutDialog;
	}

	/**
	 * This method initializes aboutContentPane
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getAboutContentPane() {
		if (aboutContentPane == null) {
			aboutContentPane = new JPanel();
			aboutContentPane.setLayout(new BorderLayout());
			aboutContentPane.setBorder(new EmptyBorder(20, 20, 20, 20));
			aboutContentPane.add(getAboutVersionLabel(), BorderLayout.CENTER);
		}
		return aboutContentPane;
	}

	/**
	 * This method initializes aboutVersionLabel	
	 * 	
	 * @return javax.swing.JLabel	
	 */
	private JLabel getAboutVersionLabel() {
		if (aboutVersionLabel == null) {
			aboutVersionLabel = new JLabel();
			
			aboutVersionLabel.setText("srxVpnManager 1.0");
			aboutVersionLabel.setHorizontalAlignment(SwingConstants.CENTER);
		}
		return aboutVersionLabel;
	}

	/**
	 * This method initializes jMenuItem	
	 * 	
	 * @return javax.swing.JMenuItem	
	 */
	private JMenuItem getAddMenuItem() {
		if (addMenuItem == null) {
			addMenuItem = new JMenuItem("Add");
			addMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,
					Event.CTRL_MASK, true));
			addMenuItem.addActionListener(this);
		}
		return addMenuItem;
	}

	/**
	 * This method initializes jMenuItem	
	 * 	
	 * @return javax.swing.JMenuItem	
	 */
	private JMenuItem getDeleteMenuItem() {
		if (deleteMenuItem == null) {
			deleteMenuItem = new JMenuItem("Delete");
			deleteMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,
					Event.CTRL_MASK, true));
			deleteMenuItem.addActionListener(this);
		}
		return deleteMenuItem;
	}

	/**
	 * This method initializes jMenuItem	
	 * 	
	 * @return javax.swing.JMenuItem	
	 */
	private JMenuItem getSaveMenuItem() {
		if (saveMenuItem == null) {
			saveMenuItem = new JMenuItem("Save");
			saveMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
					Event.CTRL_MASK, true));
			saveMenuItem.addActionListener(this);

		}
		return saveMenuItem;
	}

	/**
	 * This method initializes OpenMenuItem	
	 * 	
	 * @return javax.swing.JMenuItem	
	 */
	private JMenuItem getOpenMenuItem() {
		if (openMenuItem == null) {
			openMenuItem = new JMenuItem("Open");
			openMenuItem.addActionListener(this);
		}
		return openMenuItem;
	}

	/**
	 * This method initializes ImportMenuItem	
	 * 	
	 * @return javax.swing.JMenuItem	
	 */
	private JMenuItem getImportMenuItem() {
		if (importMenuItem == null) {
			importMenuItem = new JMenuItem("Import");
			importMenuItem.addActionListener(this);
		}
		return importMenuItem;
	}

	/**
	 * This method initializes UsersScrollPanel	
	 * 	
	 * @return javax.swing.JScrollPane	
	 */
	private JScrollPane getUsersScrollPanel() {
		if (UsersScrollPanel == null) {
			UsersScrollPanel = new JScrollPane();
			UsersScrollPanel.setViewportView(getUsersTable());
			UsersScrollPanel.setEnabled(false);
		}
		return UsersScrollPanel;
	}

	/**
	 * This method initializes UsersTable	
	 * 	
	 * @return javax.swing.JTable	
	 */
	private JTable getUsersTable() {
		if (UsersTable == null) {
			TableColumn column;
			UsersTable = new JTable(userData);
			UsersTable.getTableHeader().setReorderingAllowed(false);
			UsersTable.setRowSelectionAllowed(false);
			UsersTable.setColumnSelectionAllowed(false);
			column = UsersTable.getColumnModel().getColumn(2);
			int i = column.getMinWidth();
			column.setMaxWidth(i);
			column.setPreferredWidth(i);
			column.setResizable(false);
			
		}
		return UsersTable;
	}

	/**
	 * This method initializes StatusToolBar	
	 * 	
	 * @return javax.swing.JToolBar	
	 */
	private JToolBar getStatusToolBar() {
		if (StatusToolBar == null) {
			StatusToolBar = new JToolBar();
			StatusToolBar.add(getCommitButton());
			StatusToolBar.add(getConnectedButton());
		}
		return StatusToolBar;
	}

	/**
	 * This method initializes PreferencesMenuItem	
	 * 	
	 * @return javax.swing.JMenuItem	
	 */
	private JMenuItem getPreferencesMenuItem() {
		if (PreferencesMenuItem == null) {
			PreferencesMenuItem = new JMenuItem();
			PreferencesMenuItem.setText("Preferences");
			PreferencesMenuItem.addActionListener(this);

		}
		return PreferencesMenuItem;
	}

	/**
	 * This method initializes ConnectedButton	
	 * 	
	 * @return javax.swing.JRadioButton	
	 */
	private JRadioButton getConnectedButton() {
		if (ConnectedButton == null) {
			ConnectedButton = new JRadioButton();
			ConnectedButton.setText("Push to connect");
			ConnectedButton.setEnabled(false);
			ConnectedButton.addActionListener(this);
		}
		return ConnectedButton;
	}

	/**
	 * This method initializes CommitButton	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getCommitButton() {
		if (CommitButton == null) {
			CommitButton = new JButton();
			CommitButton.setText("Commit");
			CommitButton.setEnabled(false);
			CommitButton.addActionListener(this);
		}
		return CommitButton;
	}

	/**
	 * This method initializes addUserDialog	
	 * 	
	 * @return javax.swing.JDialog	
	 */
	private JDialog getAddUserDialog() {
		if (addUserDialog == null) {
			addUserDialog = new JDialog(getJFrame());
			addUserDialog.setTitle("New User Entry");
			addUserDialog.setSize(new Dimension(277, 118));
			addUserDialog.setContentPane(getUserPasswordPanel());
			addUserDialog.setModalityType(ModalityType.APPLICATION_MODAL);
		}
		return addUserDialog;
	}

	/**
	 * This method initializes userPasswordPanel	
	 * 	
	 * @return javax.swing.JPanel	
	 */
	private JPanel getUserPasswordPanel() {
		if (userPasswordPanel == null) {
			Insets ist = new Insets (2,10,2,10);
			
			GridBagConstraints gridBagConstraints00 = new GridBagConstraints();
			gridBagConstraints00.gridx = 0;
			gridBagConstraints00.gridy = 0;
			gridBagConstraints00.anchor = GridBagConstraints.LINE_END;
			gridBagConstraints00.insets = ist;	

			GridBagConstraints gridBagConstraints10 = new GridBagConstraints();
			gridBagConstraints10.fill = GridBagConstraints.VERTICAL;
			gridBagConstraints10.gridx = 1;
			gridBagConstraints10.gridy = 0;
			gridBagConstraints10.anchor = GridBagConstraints.LINE_START;
			gridBagConstraints10.insets = ist;
			gridBagConstraints10.fill = GridBagConstraints.HORIZONTAL;
			
			GridBagConstraints gridBagConstraints01 = new GridBagConstraints();
			gridBagConstraints01.gridx = 0;
			gridBagConstraints01.gridy = 1;
			gridBagConstraints01.anchor = GridBagConstraints.LINE_END;
			gridBagConstraints01.insets = ist;
			
			GridBagConstraints gridBagConstraints11 = new GridBagConstraints();
			gridBagConstraints11.fill = GridBagConstraints.VERTICAL;
			gridBagConstraints11.gridy = 1;
			gridBagConstraints11.gridx = 1;
			gridBagConstraints11.anchor = GridBagConstraints.LINE_START;
			gridBagConstraints11.insets = ist;
			gridBagConstraints11.fill = GridBagConstraints.HORIZONTAL;


			GridBagConstraints gridBagConstraints02 = new GridBagConstraints();
			gridBagConstraints02.gridx = 0;
			gridBagConstraints02.gridy = 2;
			gridBagConstraints02.gridwidth = 2;
			gridBagConstraints02.insets = new Insets (10,10,2,10);	
			
			userPasswordPanel = new JPanel();
			userPasswordPanel.setLayout(new GridBagLayout());
			userPasswordPanel.add(getUsernameEntryField(), gridBagConstraints10);
			userPasswordPanel.add(getPasswordEntryField(), gridBagConstraints11);
			userPasswordPanel.add(new JLabel("username"), gridBagConstraints00);
			userPasswordPanel.add(new JLabel("password"), gridBagConstraints01);
			userPasswordPanel.add(getOkCancelPanel1(), gridBagConstraints02);
		}
		return userPasswordPanel;
	}

	/**
	 * This method initializes usernameEntryField	
	 * 	
	 * @return javax.swing.JTextField	
	 */
	private JTextField getUsernameEntryField() {
		if (usernameEntryField == null) {
			usernameEntryField = new JTextField(20);
			usernameEntryField.setToolTipText("username");
		}
		return usernameEntryField;
	}

	/**
	 * This method initializes passwordEntryField	
	 * 	
	 * @return javax.swing.JPasswordField	
	 */
	private JPasswordField getPasswordEntryField() {
		if (passwordEntryField == null) {
			passwordEntryField = new JPasswordField(20);
			passwordEntryField.setToolTipText("password");
		}
		return passwordEntryField;
	}

	private JTextField getRemoteNetworkEntryField() {
		if (remoteNetworkEntryField == null) {
			remoteNetworkEntryField = new JTextField(20);
			remoteNetworkEntryField.setToolTipText("Remote Network (example: 192.168.1.0/24)");
		}
		return remoteNetworkEntryField;
	}

	private JTextField getLowIpEntryField() {
		if (remoteLowIpEntryField == null) {
			remoteLowIpEntryField = new JTextField(20);
			remoteLowIpEntryField.setToolTipText("Low IP address in range");
		}
		return remoteLowIpEntryField;
	}

	private JTextField getHighIpEntryField() {
		if (remoteHighIpEntryField == null) {
			remoteHighIpEntryField = new JTextField(20);
			remoteHighIpEntryField.setToolTipText("High IP address in range");
		}
		return remoteHighIpEntryField;
	}
	
	private JTextField getDnsIpEntryField () {
		if (remoteDnsIpAddress == null) {
			remoteDnsIpAddress = new JTextField(20);
			remoteDnsIpAddress.setToolTipText("Intranet's DNS IP address");
		}
		return remoteDnsIpAddress;
	}

	/**
	 * This method initializes okCancelPanel1	
	 * 	
	 * @return javax.swing.JPanel	
	 */
	private JPanel getOkCancelPanel1() {
		if (okCancelPanel1 == null) {
			GridBagConstraints gridBagConstraints6 = new GridBagConstraints();
			gridBagConstraints6.gridx = 1;
			gridBagConstraints6.gridy = 0;
			GridBagConstraints gridBagConstraints5 = new GridBagConstraints();
			gridBagConstraints5.gridx = 0;
			gridBagConstraints5.gridy = 0;
			okCancelPanel1 = new JPanel();
			okCancelPanel1.setLayout(new GridBagLayout());
			okCancelPanel1.add(getUserAddOkButton(), gridBagConstraints5);
			okCancelPanel1.add(getUserAddCancelButton(), gridBagConstraints6);
		}
		return okCancelPanel1;
	}

	/**
	 * This method initializes userAddOkButton	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getUserAddOkButton() {
		if (userAddOkButton == null) {
			userAddOkButton = new JButton();
			userAddOkButton.setText("OK");
			userAddOkButton.addActionListener(this);
		}
		return userAddOkButton;
	}

	/**
	 * This method initializes userAddCancelButton	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getUserAddCancelButton() {
		if (userAddCancelButton == null) {
			userAddCancelButton = new JButton();
			userAddCancelButton.setText("Cancel");
			userAddCancelButton.addActionListener(this);
		}
		return userAddCancelButton;
	}

	/**
	 * This method initializes PreferencesDialog	
	 * 	
	 * @return javax.swing.JDialog	
	 */
	private JDialog getPreferencesDialog() {
		if (PreferencesDialog == null) {
			PreferencesDialog = new JDialog(getJFrame());
			PreferencesDialog.setSize(new Dimension(295, 144));
			PreferencesDialog.setTitle("Preferences");
			PreferencesDialog.setContentPane(getPreferenceFieldsPanel());
			PreferencesDialog.setModalityType(ModalityType.APPLICATION_MODAL);

		}
		return PreferencesDialog;
	}

	/**
	 * This method initializes preferenceFieldsPanel	
	 * 	
	 * @return javax.swing.JPanel	
	 */
	private JPanel getPreferenceFieldsPanel() {
		if (preferenceFieldsPanel == null) {
			Insets ist = new Insets(2,10,2,10);
			GridBagConstraints gbc[][] = new GridBagConstraints[2][7];
			GridBagConstraints downGbc = new GridBagConstraints();
			for (int i=0; i<7; i++) {
				gbc[0][i] = new GridBagConstraints();
				gbc[0][i].gridx = 0;
				gbc[0][i].gridy = i;
				gbc[0][i].anchor = GridBagConstraints.LINE_END;
				gbc[0][i].insets = ist;			
				gbc[1][i] = new GridBagConstraints();
				gbc[1][i].gridx = 1;
				gbc[1][i].gridy = i;
				gbc[1][i].anchor = GridBagConstraints.LINE_START;
				gbc[1][i].insets = ist;			
			}
			downGbc = new GridBagConstraints();
			downGbc.gridx = 0;
			downGbc.gridy = 7;
			downGbc.gridwidth = 2;
			downGbc.anchor = GridBagConstraints.CENTER;
			downGbc.insets = ist;			
			
			preferenceFieldsPanel = new JPanel();
			preferenceFieldsPanel.setLayout(new GridBagLayout());
			preferenceFieldsPanel.add(new JLabel("Hostname"), gbc[0][0]);
			preferenceFieldsPanel.add(new JLabel("Admin username"), gbc[0][1]);
			preferenceFieldsPanel.add(new JLabel("Admin password"), gbc[0][2]);
			preferenceFieldsPanel.add(new JLabel("dvpn network"), gbc[0][3]);
			preferenceFieldsPanel.add(new JLabel("dvpn low IP"), gbc[0][4]);
			preferenceFieldsPanel.add(new JLabel("dvpn high IP"), gbc[0][5]);
			preferenceFieldsPanel.add(new JLabel("dvpn DNS IP address"), gbc[0][6]);
			preferenceFieldsPanel.add(getIpAddressEntryField(), gbc[1][0]);
			preferenceFieldsPanel.add(getAdminUserEntryField(), gbc[1][1]);
			preferenceFieldsPanel.add(getAdminPassowrdEntryField(), gbc[1][2]);
			preferenceFieldsPanel.add(getRemoteNetworkEntryField(), gbc[1][3]);
			preferenceFieldsPanel.add(getLowIpEntryField(), gbc[1][4]);
			preferenceFieldsPanel.add(getHighIpEntryField(), gbc[1][5]);
			preferenceFieldsPanel.add(getDnsIpEntryField(), gbc[1][6]);
			preferenceFieldsPanel.add(getPreferencesOkCancelPanel(), downGbc);
		}
		return preferenceFieldsPanel;
	}

	/**
	 * This method initializes ipAddressEntryField	
	 * 	
	 * @return javax.swing.JTextField	
	 */
	private JTextField getIpAddressEntryField() {
		if (ipAddressEntryField == null) {
			ipAddressEntryField = new JTextField(20);
			ipAddressEntryField.setToolTipText("SRX hostname or IP address");
		}
		return ipAddressEntryField;
	}

	/**
	 * This method initializes adminUserEntryField	
	 * 	
	 * @return javax.swing.JTextField	
	 */
	private JTextField getAdminUserEntryField() {
		if (adminUserEntryField == null) {
			adminUserEntryField = new JTextField(20);
			adminUserEntryField.setToolTipText("junos username with enough rights");
		}
		return adminUserEntryField;
	}

	/**
	 * This method initializes adminPassowrdEntryField	
	 * 	
	 * @return javax.swing.JPasswordField	
	 */
	private JPasswordField getAdminPassowrdEntryField() {
		if (adminPasswordEntryField == null) {
			adminPasswordEntryField = new JPasswordField(20);
			adminPasswordEntryField.setToolTipText("junos username's password");
		}
		return adminPasswordEntryField;
	}

	/**
	 * This method initializes preferencesOkCancelPanel	
	 * 	
	 * @return javax.swing.JPanel	
	 */
	private JPanel getPreferencesOkCancelPanel() {
		if (preferencesOkCancelPanel == null) {
			GridBagConstraints gridBagConstraints14 = new GridBagConstraints();
			gridBagConstraints14.gridx = 1;
			gridBagConstraints14.gridy = 0;
			GridBagConstraints gridBagConstraints13 = new GridBagConstraints();
			gridBagConstraints13.gridx = 0;
			gridBagConstraints13.gridy = 0;
			preferencesOkCancelPanel = new JPanel();
			preferencesOkCancelPanel.setLayout(new GridBagLayout());
			preferencesOkCancelPanel.add(getPreferencesOkButton(), gridBagConstraints13);
			preferencesOkCancelPanel.add(getPreferencesCancelButton(), gridBagConstraints14);
		}
		return preferencesOkCancelPanel;
	}

	/**
	 * This method initializes preferencesOkButton	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getPreferencesOkButton() {
		if (preferencesOkButton == null) {
			preferencesOkButton = new JButton();
			preferencesOkButton.setText("OK");
			preferencesOkButton.addActionListener(this);
		}
		return preferencesOkButton;
	}

	/**
	 * This method initializes preferencesCancelButton	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getPreferencesCancelButton() {
		if (preferencesCancelButton == null) {
			preferencesCancelButton = new JButton();
			preferencesCancelButton.setText("Cancel");
			preferencesCancelButton.addActionListener(this);
		}
		return preferencesCancelButton;
	}

	/**
	 * This method initializes errorDialog	
	 * 	
	 * @return javax.swing.JDialog	
	 */
	private JDialog getErrorDialog() {
		if (errorDialog == null) {
			errorDialog = new JDialog(getJFrame());
			errorDialog.setSize(new Dimension(123, 69));
			errorDialog.setTitle("Error");
			errorDialog.setContentPane(getErrorDialogContentPane());
			errorDialog.setModalityType(ModalityType.APPLICATION_MODAL);
			errorDialog.addWindowListener(this);
		}
		return errorDialog;
	}

	/**
	 * This method initializes errorDialogContentPane	
	 * 	
	 * @return javax.swing.JPanel	
	 */
	private JPanel getErrorDialogContentPane() {
		if (errorDialogContentPane == null) {
			errorDialogContentPane = new JPanel();
			errorDialogContentPane.setBorder(new EmptyBorder(20, 20, 20, 20));
			errorDialogContentPane.setLayout(new BorderLayout());
			errorDialogContentPane.add(errorDialogText, BorderLayout.CENTER);
		}
		return errorDialogContentPane;
	}

	/**
	 * Launches this application
	 * @throws UnsupportedLookAndFeelException 
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 * @throws ClassNotFoundException 

	 */
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException {

		UIManager.setLookAndFeel(
	            UIManager.getSystemLookAndFeelClassName());
		
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				MainWindow application = new MainWindow();
				application.getJFrame().setVisible(true);
			}
		});
	}
	

	@SuppressWarnings("unchecked")
	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource().equals(ConnectedButton)) {
			stateMachine(TR_PUSHCONNECT);
		}
		if (e.getSource().equals(CommitButton)) {
			stateMachine(TR_PUSHCOMMIT);
		}
		if (e.getSource().equals(exitMenuItem)) {
			System.exit(0);
		}
		if (e.getSource().equals(aboutMenuItem)) {
			getAboutDialog().pack();
			getAboutDialog().setLocationRelativeTo(getJFrame());
			getAboutDialog().setVisible(true);
		}
		if (e.getSource().equals(addMenuItem)) {
			getAddUserDialog().pack();
			getAddUserDialog().setLocationRelativeTo(getJFrame());
			getAddUserDialog().setVisible(true);
		}
		if (e.getSource().equals(deleteMenuItem)){
			purgeRealData();
		}
		if (e.getSource().equals(saveMenuItem)) {
			try {
				preferencesFile.saveUsers(usersData);
			} catch (Exception e1) {
				showErrorDialog(e1.getMessage());
			}
		}
		if (e.getSource().equals(openMenuItem)) {
			Document iUsers = null;
			Boolean importErrors = false;
			try {
				iUsers = preferencesFile.openUsers(xsdOpen);
			} catch (Exception e1) {
				showErrorDialog(e1.getMessage());
				return;
			}
			if (iUsers != null) {
				usersData.detachRootElement();
				usersData = iUsers;
				profileElement = usersData.getRootElement();
				Iterator <Element>i = profileElement.getDescendants(new ElementFilter("client"));
				while (i.hasNext()) {
				    Element j = i.next();
				    Element jpw = j.getChild("firewall-user").getChild("password");
				    try {
						jpw.setText(bc.getDecryptedPassword(jpw.getAttributeValue("cryptopassword")));
					} catch (Exception e1) {
						// There is an error with the password so we'll mark the imported record as ready to delete
						j.setAttribute("selected", "true");
						importErrors = true;
						showErrorDialog("Error importing client name = "+j.getChildText("name"));
					}
				}
				if (importErrors) purgeRealData();
				userData.fireTableDataChanged();
			}
		}
		if (e.getSource().equals(importMenuItem)) {
			Document iUsers = null;
			Boolean importErrors = false;
			try {
				iUsers = preferencesFile.openUsers(xsdImport);
			} catch (Exception e2) {
				showErrorDialog(e2.getMessage());
				return;
			}
			if (iUsers != null) {
				usersData.detachRootElement();
				usersData = iUsers;
				profileElement = usersData.getRootElement();
				Iterator <Element>i = profileElement.getDescendants(new ElementFilter("client"));
				while (i.hasNext()) {
				    Element j = i.next();
				    Element jpw = j.getChild("firewall-user").getChild("password");
				    try {
						jpw.setAttribute("cryptopassword",bc.getCryptoPassword(jpw.getText()));
					} catch (Exception e1) {
						// There is an error with the password so we'll mark the imported record as ready to delete
						j.setAttribute("selected", "true");
						importErrors = true;
						showErrorDialog("Error importing client name = "+j.getChildText("name"));
					}
				}
				if (importErrors) purgeRealData();
				userData.fireTableDataChanged();
			}
		}
		if (e.getSource().equals(PreferencesMenuItem)) {
			getPreferencesDialog().pack();
			getPreferencesDialog().setLocationRelativeTo(getJFrame());
			getPreferencesDialog().setVisible(true);
		}
		if (e.getSource().equals(userAddOkButton)) {
			String password = new String(passwordEntryField.getPassword());
			Element client = new Element("client");
			Element name = new Element("name");
			name.setText(usernameEntryField.getText());
			client.addContent(name);
			Element fwuser = new Element("firewall-user");
			Element pw = new Element("password");
			pw.setText(password);
			pw.setAttribute("cryptopassword", bc.getCryptoPassword(password));
			fwuser.addContent(pw);
			client.addContent(fwuser);
			profileElement.addContent(client);
			addUserDialog.setVisible(false);
			userData.fireTableDataChanged();
		}
		if (e.getSource().equals(userAddCancelButton)) {
			addUserDialog.setVisible(false);
		}
		if (e.getSource().equals(preferencesOkButton)){
			stateMachine(TR_PREFLOADOK);
			PreferencesDialog.setVisible(false);
		}
		if (e.getSource().equals(preferencesCancelButton)) {
			PreferencesDialog.setVisible(false);
		}
	}
	
	private void showErrorDialog (String error) {
		errorDialogText.setText(error);
		getErrorDialog().pack();
		getErrorDialog().setLocationRelativeTo(getJFrame());
		getErrorDialog().setVisible(true);
	}
	private void purgeRealData () {
	    Document deleted = null;
		try {
			deleted = xlsPurger.transform(usersData);
		} catch (XSLTransformException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		usersData.detachRootElement();
		usersData.setRootElement(deleted.detachRootElement());
		profileElement=usersData.getRootElement();
	    userData.fireTableDataChanged();
	}
	
	private AbstractTableModel userData = new AbstractTableModel() {

		@Override
		public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
			if (columnIndex == 2) {
				Element k = ((Element) profileElement.getChildren().get(rowIndex)); 
				if ( k.getAttribute("selected") == null ) k.setAttribute("selected", "true");
				else k.removeAttribute("selected");
			}
		}

		private static final long serialVersionUID = 1L; 
		public int getColumnCount() { return 3; }
		public int getRowCount() {
			return profileElement.getChildren().size();
			}
		
		@Override
		public String getColumnName(int c) {
			if (c == 0) return "Username";
			else if (c == 1) return "Password";
			else return "";
		}
		
		@Override
		public Class<?> getColumnClass(int columnIndex) {
			if (columnIndex == 2) return Boolean.class;
			else return String.class;
		}
		
		@Override
		public boolean isCellEditable(int arg0, int arg1) {
			if (arg1 == 2) return true;
			return false;
		}
		
		public Object getValueAt ( int row, int col ) {
			Element e = (Element) profileElement.getChildren().get(row);
			if (col == 0) {
				return e.getChildText("name");
			}
			if (col == 1) {
				return e.getChild("firewall-user").getChild("password").getAttributeValue("cryptopassword");

			}
			if ( col == 2) {
				if (e.getAttributeValue("selected") == null ) return false;
				else return true;
			}
			return null;
			}
	};

	@Override
	public void windowActivated(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowClosed(WindowEvent arg0) {
	}

	@Override
	public void windowClosing(WindowEvent arg0) {
		if ( arg0.getSource() == getErrorDialog()){
			stateMachine(TR_DIALOGCLOSE);
		}
	}

	@Override
	public void windowDeactivated(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowDeiconified(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowIconified(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void windowOpened(WindowEvent arg0) {
		// TODO Auto-generated method stub
		
	}
}
